package com.gopay.common.solution.util;

import com.gopay.common.cache.client.RedisClient;
import com.gopay.common.constants.Constants;
import com.gopay.common.constants.poundage.FeeDtlStatus;
import com.gopay.common.constants.poundage.FeeType;
import com.gopay.common.constants.solution.SolutionTypeConstant;
import com.gopay.common.solution.vo.CacheFeeDtlInfo;
import com.gopay.common.util.FastJsonUtil;
import com.gopay.common.util.NumberUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.math.BigDecimal;

/**
 *手续费计算方法
 * @Author jianghp
 * @Description
 * @Date 2016/8/25
 */
public class CalculateFeeUtil {

    protected static Log logger = LogFactory.getLog(CalculateFeeUtil.class);

    /**
     * 计费方式
     * 0 - 年费 1 - 订单成交金额区间比率收费 2 - 按笔收费 3 - 订单成交金额区间定额收费
     */
    public static BigDecimal amt(CacheFeeDtlInfo dtl, BigDecimal amt, String payChannel, String intTxnCd, String acctType,String bankCode,String acctId,boolean cacheFlag,String redisEnvironment,String prodCode) {

        if (!(StringUtils.equals(dtl.getAcctType(), acctType)
                && StringUtils.equals(dtl.getPayChannel(), payChannel)
                && StringUtils.equals(dtl.getGopayIntTxnCd(), intTxnCd)
                && StringUtils.equals(dtl.getDtlStatus(), FeeDtlStatus._00.value)
        )) {
            return null;
        }

        logger.info("判断能否进入设置缓存手续费，cacheFlag:"+cacheFlag+",redisEnvironment:"+redisEnvironment+",prodCode:"+prodCode+",acctId:"+acctId+",bankCode:"+bankCode);
        if(cacheFlag){
            String key = FastJsonUtil.getKey(redisEnvironment,Constants.CACHE_CHANNEL_SOLUTION,prodCode,intTxnCd,SolutionTypeConstant.TRANS_FEE);
            String field = FastJsonUtil.getSolutionField(acctId, payChannel);
            logger.info("进入设置缓存手续费，key:【"+key+"】,field:【"+field+"】");
            //手续费明细加入缓存
            RedisClient.hset(key, field,dtl,3600*24); //一天有效
        }

        BigDecimal fee = new BigDecimal("0.00");

        String feeType_ = dtl.getFeeType();
        if(null == feeType_){
            logger.error("无效的feeType：" + dtl.toString());
            return null;
        }

        // 不收费
        if (feeType_.equals(FeeType._N.value)){
            return fee;
        }
        // 年费
        if (feeType_.equals(FeeType._0.value)){
            return fee;
        }
        // 增加单银行特例手续费的计算  add  by jianghoup start
        logger.info("手续费计算开始： 【FeeDtlInfo】");
        logger.info("手续费计算，amt: " + amt + ", bankCode: " + bankCode);
        // 按笔
        if (feeType_.equals(FeeType._2.value)) {
            return calculationAsNum(dtl,bankCode,fee);
        }
        // 比例
        if (feeType_.equals(FeeType._1.value)) {
            return calculationAsProportion(dtl, bankCode, fee, amt);
        }
        // 定额
        if (feeType_.equals(FeeType._3.value)) {
            return calculationAsQuota(dtl,bankCode,fee,amt);
        }
        return null;
    }

    /**
     * 按比例计算手续费   加单银行特例的计算  add by jianghoup
     */
    private static BigDecimal calculationAsProportion(CacheFeeDtlInfo dtl, String bankCode, BigDecimal fee, BigDecimal amt) {
        String specType = dtl.getSpecType(); //是否启动单银行特例手续费
        if(StringUtils.isEmpty(bankCode)) {
            return calculationAsProportionCommon(dtl.getCalExp(), fee, amt, "#");
        }else if(StringUtils.isEmpty(specType)||(FeeType._1.value+"0").equalsIgnoreCase(specType)){//不启用
            return calculationAsProportionCommon(dtl.getCalExp(), fee, amt, "#");
        }else{ //启用
            String specExp = dtl.getSpecExp();
            if(StringUtils.isEmpty(specExp)){
                return calculationAsProportionCommon(dtl.getCalExp(), fee, amt, "#");
            }else{
                if(specExp.toUpperCase().indexOf(bankCode.toUpperCase())<0){
                    return calculationAsProportionCommon(dtl.getCalExp(), fee, amt, "#");
                }else{
                    String[] specExpArr = specExp.split("#");
                    for(String currentExp : specExpArr){
                        if(currentExp.toUpperCase().startsWith(bankCode.toUpperCase())){
                            String currentFeeStr = currentExp.substring(currentExp.indexOf("@")+1,currentExp.length());
                            return calculationAsProportionCommon(currentFeeStr, fee, amt, "&");
                        }
                    }
                }
            }
        }
        logger.error("手续费计算错误，amt: " + amt + ", calExp: " + dtl.getCalExp());
        return null;
    }

    /**
     * 按比例计算手续费  通用方法  add by jianghoup
     */
    private static BigDecimal calculationAsProportionCommon(String exp, BigDecimal fee, BigDecimal amt,String reg){
        String[] ranges = StringUtils.split(exp, reg);
        for (String range : ranges) {
            String[] param = StringUtils.split(range, '-');
            BigDecimal start = new BigDecimal(param[0]);// 起始
            String endStr = param[1];// 结束
            BigDecimal end = StringUtils.equals("+", endStr) ? new BigDecimal(String.valueOf(Long.MAX_VALUE))
                    : new BigDecimal(endStr);
            if (amt.compareTo(start) >= 0 && amt.compareTo(end) < 0) {
                BigDecimal sacle = new BigDecimal(param[2]);// 百分比
                if(sacle.compareTo(NumberUtils.getZero()) > 0){
                    fee = amt.multiply(sacle).divide(new BigDecimal(100));
                }

                BigDecimal min = new BigDecimal(param[3]);
                BigDecimal max = new BigDecimal(param[4]);
                if (fee.compareTo(min) < 0) {
                    fee = min;
                }
                if (fee.compareTo(max) > 0) {
                    fee = max;
                }
                if(null == fee || fee.compareTo(NumberUtils.getZero()) < 0){
                    fee = NumberUtils.getZero();
                }
                return fee.setScale(2, BigDecimal.ROUND_HALF_UP);
            }
        }

        logger.error("手续费计算错误，amt: " + amt + ", calExp: " + exp);
        return null;
    }

    /**
     * 按区间定额计算手续费   加单银行特例的计算  add by jianghoup
     */
    private static BigDecimal calculationAsQuota(CacheFeeDtlInfo dtl, String bankCode, BigDecimal fee, BigDecimal amt) {
        String specType = dtl.getSpecType(); //是否启动单银行特例手续费
        if(StringUtils.isEmpty(bankCode)) {
            return calculationAsQuotaCommon(dtl.getCalExp(), fee, amt, "#");
        }else if(StringUtils.isEmpty(specType)||(FeeType._3.value+"0").equalsIgnoreCase(specType)){//不启用
            return calculationAsQuotaCommon(dtl.getCalExp(), fee, amt, "#");
        }else{ //启用
            String specExp = dtl.getSpecExp();
            if(StringUtils.isEmpty(specExp)){
                return calculationAsQuotaCommon(dtl.getCalExp(), fee, amt, "#");
            }else{
                if(specExp.toUpperCase().indexOf(bankCode.toUpperCase())<0){
                    return calculationAsQuotaCommon(dtl.getCalExp(), fee, amt, "#");
                }else{
                    String[] specExpArr = specExp.split("#");
                    for(String currentExp : specExpArr){
                        if(currentExp.toUpperCase().startsWith(bankCode.toUpperCase())){
                            String currentFeeStr = currentExp.substring(currentExp.indexOf("@")+1,currentExp.length());
                            return calculationAsQuotaCommon(currentFeeStr, fee, amt, "&");
                        }
                    }
                }
            }
        }
        logger.error("手续费计算错误，amt: " + amt + ", calExp: " + dtl.getCalExp());
        return null;
    }

    /**
     * 按区间定额计算手续费  通用方法  add by jianghoup
     */
    private  static BigDecimal calculationAsQuotaCommon(String exp, BigDecimal fee, BigDecimal amt,String reg){
        String[] ranges = StringUtils.split(exp, reg);
        for (String range : ranges) {
            String[] param = StringUtils.split(range, '-');
            BigDecimal start = new BigDecimal(param[0]);// 起始值
            String endStr = param[1];
            BigDecimal end = StringUtils.equals("+", endStr) ? new BigDecimal(String.valueOf(Long.MAX_VALUE))
                    : new BigDecimal(endStr);// 结束值
            if (amt.compareTo(start) >= 0 && amt.compareTo(end) < 0) {
                fee = fee.add(new BigDecimal(param[2]));
                return fee;
            }
        }
        logger.error("手续费计算错误，amt: " + amt + ", calExp: " + exp);
        return null;
    }

    /**
     * 按笔计算手续费   加单银行特例的计算  add by jianghoup
     */
    private static BigDecimal calculationAsNum(CacheFeeDtlInfo dtl, String bankCode,BigDecimal fee ) {
        String specType = dtl.getSpecType(); //是否启动单银行特例手续费
        if(StringUtils.isEmpty(bankCode)) {
            return fee.add(new BigDecimal(dtl.getCalExp()));
        }else if(StringUtils.isEmpty(specType)||(FeeType._2.value+"0").equalsIgnoreCase(specType)){//不启用
            return fee.add(new BigDecimal(dtl.getCalExp()));
        }else{ //启用
            String specExp = dtl.getSpecExp();
            if(StringUtils.isEmpty(specExp)){
                return fee.add(new BigDecimal(dtl.getCalExp()));
            }else{
                if(specExp.toUpperCase().indexOf(bankCode.toUpperCase())<0){
                    return fee.add(new BigDecimal(dtl.getCalExp()));
                }else{
                    String[] specExpArr = specExp.split("#");
                    for(String currentExp : specExpArr){
                        if(currentExp.toUpperCase().startsWith(bankCode.toUpperCase())){
                            String currentFeeStr = currentExp.substring(currentExp.indexOf("-")+1,currentExp.length());
                            return fee.add(new BigDecimal(currentFeeStr));
                        }
                    }
                }
                return fee.add(new BigDecimal(dtl.getCalExp()));
            }
        }
    }
}
